home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume13 / attpc.renice < prev    next >
Encoding:
Internet Message Format  |  1988-01-31  |  9.3 KB

  1. Subject:  v13i070:  Change process priority on ATT PC
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: kenobi!fork (Mike Ditto)
  7. Posting-number: Volume 13, Issue 70
  8. Archive-name: attpc.renice
  9.  
  10. Here is the 'renice' command, which alters the priority ('nice' value) of
  11. a running process.  The source as written is for the Unix PC, but is fairly
  12. portable (see below).
  13.  
  14. This program is contributed primarily as an example of the methods used to
  15. write to the kernel's internal tables.  In this case, a field in an element
  16. of the 'proc' array inside the kernel is changed.
  17.  
  18. Verify that the macros in "Makefile" are correct for you (LBIN, for example
  19. should be where you want the program to be installed), and run 'make' AS ROOT.
  20. It is important to do the make as root so that the resulting program will
  21. have the set-uid bit set, allowing it to read and write the kernel's memory.
  22.  
  23.  
  24. Some notes to anyone who wants to port this program to something other
  25. than the Unix PC:
  26.  
  27. The Unix PC has "tunable kernel parameters", which mean that things that
  28. are constants on most older Unix systems are variable.  This version of
  29. fuser reads the values of these variables from the kernel's memory.  I have
  30. tried to make most of this transparent, for ease of porting to a more plain-
  31. vanilla Unix.  For example, I have an 'int' variable called 'NPROC', which
  32. emulates the #define present in 'standard' Unix.  To make renice run on such
  33. systems, it should be possible to remove this variable and the code that sets
  34. it, and the program will use the #define from <sys/*.h>.  Also get rid of the
  35. <sys/tune.h> include and anything referencing 'tuhi'.
  36.  
  37.  
  38.                     -=] Ford [=-
  39.  
  40. "There's enough money here        (In Real Life:  Michael Ditto)
  41.  to buy 5000 cans of Noodle-Roni!"    ford%kenobi@crash.CTS.COM
  42.   -- Zippy the Pinhead            ...!crash!kenobi!ford
  43.  
  44.  
  45. Here's the shar file:
  46.  
  47. #! /bin/sh
  48. # This is a shell archive, meaning:
  49. # 1. Remove everything above the #! /bin/sh line.
  50. # 2. Save the resulting text in a file.
  51. # 3. Execute the file with /bin/sh (not csh) to create the files:
  52. #    renice.1
  53. #    Makefile
  54. #    renice.c
  55. export PATH; PATH=/bin:$PATH
  56. echo shar: extracting "'renice.1'" '(1222 characters)'
  57. if test -f 'renice.1'
  58. then
  59.     echo shar: will not over-write existing file "'renice.1'"
  60. else
  61. cat << \SHAR_EOF > 'renice.1'
  62. .TH RENICE 1
  63. .SH NAME
  64. renice \- change the priority of a running program
  65. .SH SYNOPSIS
  66. .B renice
  67. [{+-}inc] [=prio] pid ...
  68. .SH DESCRIPTION
  69. .I Renice
  70. modifies the kernel's internal process table to change the 'nice' value
  71. of the listed process IDs.  The priority may be increased,
  72. decreased, or set to an absolute number.
  73. .P
  74. Only the super-user can increase the priority of a process, or change the
  75. priority of another user's process.
  76. .SH OPTIONS
  77. Giving
  78. .B -inc
  79. causes the priority to decrease by `inc'.  Giving
  80. .B +inc
  81. causes the priority to increase by `inc'.  Giving
  82. .B =prio
  83. causes the priority to be set to `prio'.  
  84. .P
  85. The changes to the priority may be re-specified between process IDs.  The
  86. default change is to add 5 to the 'niceness' of the processes (decrease its
  87. priority by 5).
  88. .SH EXAMPLES
  89. $ nroff -man -T37 renice.1 > /tmp/renice.manpage &
  90. .br
  91. [1] 1234
  92. .br
  93. renice 1234
  94. .br
  95. .RS
  96. These commands start a nroff in the background, and then change its priority
  97. so that it will not slow down work done in the foreground.  The same effect
  98. would have resulted from typing 'nice' before the nroff command, but this
  99. example assumes that the user 'forgot' to lower the priority until the
  100. program  was already running.
  101. .RE
  102. SHAR_EOF
  103. if test 1222 -ne "`wc -c < 'renice.1'`"
  104. then
  105.     echo shar: error transmitting "'renice.1'" '(should have been 1222 characters)'
  106. fi
  107. fi # end of overwriting check
  108. echo shar: extracting "'Makefile'" '(171 characters)'
  109. if test -f 'Makefile'
  110. then
  111.     echo shar: will not over-write existing file "'Makefile'"
  112. else
  113. cat << \SHAR_EOF > 'Makefile'
  114. SHELL=/bin/sh
  115. INSTALL=ln
  116. LBIN=/usr/lbin
  117. CFLAGS=-O
  118.  
  119. renice : renice.o
  120.     $(CC) $(CFLAGS) -o renice renice.o
  121.     chmod 4755 renice
  122.     chown root renice
  123.     $(INSTALL) renice $(LBIN)
  124.  
  125. SHAR_EOF
  126. if test 171 -ne "`wc -c < 'Makefile'`"
  127. then
  128.     echo shar: error transmitting "'Makefile'" '(should have been 171 characters)'
  129. fi
  130. fi # end of overwriting check
  131. echo shar: extracting "'renice.c'" '(4916 characters)'
  132. if test -f 'renice.c'
  133. then
  134.     echo shar: will not over-write existing file "'renice.c'"
  135. else
  136. cat << \SHAR_EOF > 'renice.c'
  137. /************************************************************
  138.  *
  139.  * This program was written by me, Mike "Ford" Ditto, and
  140.  * I hereby release it into the public domain in the interest
  141.  * of promoting the development of free, quality software
  142.  * for the hackers and users of the world.
  143.  *
  144.  * Feel free to use, copy, modify, improve, and redistribute
  145.  * this program, but keep in mind the spirit of this
  146.  * contribution; always provide source, and always allow
  147.  * free redistribution (shareware is fine with me).  If
  148.  * you use a significant part of this code in a program of
  149.  * yours, I would appreciate being given the appropriate
  150.  * amount of credit.
  151.  *                -=] Ford [=-
  152.  *
  153.  ************************************************************/
  154.  
  155. #include <stdio.h>
  156. #include <fcntl.h>
  157. #include <ctype.h>
  158. #include <errno.h>
  159. #include <pwd.h>
  160. #include <grp.h>
  161. #include <sys/types.h>
  162. #include <sys/param.h>
  163. #include <sys/tune.h>
  164. #include <sys/proc.h>
  165. #include <nlist.h>
  166.  
  167.  
  168. extern long lseek();
  169. extern void perror(), exit();
  170.  
  171.  
  172. void kcopy(), kwrite();
  173.  
  174. char *progname;
  175.  
  176. #define tuhiaddr (mysyms[0].n_value)
  177. #define procaddr (mysyms[1].n_value)
  178.  
  179. struct nlist mysyms[] =
  180. {
  181.     { "tuhi", },
  182.     { "proc", },
  183.     { (char *)0, },
  184. };
  185.  
  186. char buf[BUFSIZ];
  187.  
  188. int kmem;
  189. int myuid;
  190. int NPROC;
  191. static struct proc proc;
  192.  
  193.  
  194. void usage()
  195. {
  196.     fprintf(stderr,
  197.         "usage:    %s [{+-}inc] [=prio] pid ...\n", progname);
  198.     exit(-1);
  199. }
  200.  
  201.  
  202. main(argc, argv)
  203. int argc;
  204. char *argv[];
  205. {
  206.     int status=0;
  207.     int pid, relative, value;
  208.  
  209.     progname = *argv;
  210.  
  211.     setup();
  212.  
  213.     relative = 1;
  214.     value = 5;
  215.  
  216.     while (++argv,--argc)
  217.     switch (argv[0][0])
  218.     {
  219.     case '-':
  220.         if (sscanf(argv[0]+1, "%d", &value) != 1)
  221.         usage();
  222.         relative = 1;
  223.         break;
  224.     case '+':
  225.         if (sscanf(argv[0]+1, "%d", &value) != 1)
  226.         usage();
  227.         value = -value;
  228.         relative = 1;
  229.         break;
  230.     case '=':
  231.         if (sscanf(argv[0]+1, "%d", &value) != 1)
  232.         usage();
  233.         relative = 0;
  234.         break;
  235.     default:
  236.         if (sscanf(argv[0], "%d", &pid) != 1)
  237.         usage();
  238.         status += renice(pid, value, relative);
  239.     }
  240.  
  241.     return status;
  242. }
  243.  
  244.  
  245. /* one-time setup of main data structures from the kernel */
  246. setup()
  247. {
  248.     struct tunable tune;
  249.  
  250.     if ( (kmem=open("/dev/kmem", O_RDWR)) < 0 )
  251.     {
  252.     sprintf(buf, "%s: can't open /dev/kmem", progname);
  253.     perror(buf);
  254.     exit(1);
  255.     }
  256.  
  257.     if (nlist("/unix", mysyms))
  258.     {
  259.     sprintf(buf, "%s: can't nlist /unix", progname);
  260.     perror(buf);
  261.     exit(1);
  262.     }
  263.  
  264.     myuid = getuid();
  265.     setuid(myuid);
  266.  
  267. #ifdef DEBUG
  268.     fprintf(stderr, "tuhi:    0x%08lx\n", tuhiaddr);
  269. #endif DEBUG
  270.     kcopy((char *)&tune, tuhiaddr, (long) sizeof tune);
  271.  
  272.     /* do indirection on the proc address, since it */
  273.     /* is just a pointer in the kernel */
  274.     kcopy((char *)&procaddr, procaddr, (long) sizeof procaddr);
  275.  
  276. #ifdef DEBUG
  277.     fprintf(stderr, "proc:    0x%08lx\n", procaddr);
  278. #endif DEBUG
  279.  
  280.     NPROC = tune.nproc;
  281.  
  282. #ifdef DEBUG
  283.     fprintf(stderr, "NPROC:    %d\n", NPROC);
  284. #endif DEBUG
  285. }
  286.  
  287.  
  288. /* copy bytes from kernel address space to this process */
  289. void kcopy(caddr, kaddr, nbytes)
  290. char *caddr;
  291. long kaddr;
  292. long nbytes;
  293. {
  294.     if ( lseek(kmem, kaddr, 0)<0L ||
  295.     read(kmem, caddr, (unsigned)nbytes) != nbytes )
  296.     {
  297.     sprintf(buf, "%s: can't read /dev/kmem", progname);
  298.     perror(buf);
  299.     exit(1);
  300.     }
  301. }
  302.  
  303.  
  304. /* write bytes from this process' address space to the kernel's */
  305. void kwrite(kaddr, caddr, nbytes)
  306. long kaddr;
  307. char *caddr;
  308. long nbytes;
  309. {
  310. #ifdef DEBUG
  311.     fprintf(stderr, "Writing %ld bytes to kernel address 0x%08lx\n",
  312.         nbytes, kaddr);
  313. #endif
  314.  
  315.     if ( lseek(kmem, kaddr, 0)<0L ||
  316.     write(kmem, caddr, (unsigned)nbytes) != nbytes )
  317.     {
  318.     sprintf(buf, "%s: can't write /dev/kmem", progname);
  319.     perror(buf);
  320.     exit(1);
  321.     }
  322. }
  323.  
  324.  
  325. /* change the nice value of process `pid' based on 'value' and 'relative' */
  326. renice(pid, value, relative)
  327. int pid, value, relative;
  328. {
  329.     register i;
  330.     int tmpnice;
  331.  
  332.     for ( i=0 ; i<NPROC ; ++i )
  333.     {
  334.     kcopy((char *)&proc,
  335.           (long)&((struct proc *)procaddr)[i],
  336.           (long)sizeof proc);
  337.     if ( proc.p_pid == pid )
  338.     {
  339. #ifdef DEBUG
  340.         fprintf(stderr, "Found it!  proc[%d], p_uid is %d\n",
  341.            i, proc.p_uid);
  342.  
  343.         fprintf(stderr, "Old p_nice was %d\n", proc.p_nice);
  344. #endif DEBUG
  345.  
  346.         tmpnice = proc.p_nice;
  347.  
  348.         if (relative)
  349.         tmpnice += value;
  350.         else
  351.         tmpnice = value;
  352.  
  353.         if (tmpnice >= 40)
  354.         tmpnice = 40;
  355.         if (tmpnice < 0)
  356.         tmpnice = 0;
  357.  
  358. #ifdef DEBUG
  359.         fprintf(stderr, "New p_nice is %d\n", tmpnice);
  360. #endif DEBUG
  361.  
  362.         if ( myuid && (myuid != proc.p_uid || tmpnice<proc.p_nice) )
  363.         {
  364.         errno = EACCES;
  365.         sprintf(buf, "%s: can't renice process %d", progname, pid);
  366.         perror(buf);
  367.         return 1;
  368.         }
  369.  
  370.         proc.p_nice = tmpnice;
  371.  
  372.         kwrite((long)&((struct proc *)procaddr)[i]
  373.            + ( ((char *)&proc.p_nice) - (char *)&proc ),
  374.            (char *)&proc.p_nice,
  375.            (long)sizeof proc.p_nice);
  376.         return 0;
  377.     }
  378.     }
  379.  
  380.     fprintf(stderr, "%s: process %d not found.\n", progname, pid);
  381.  
  382.     return 1;
  383. }
  384. SHAR_EOF
  385. if test 4916 -ne "`wc -c < 'renice.c'`"
  386. then
  387.     echo shar: error transmitting "'renice.c'" '(should have been 4916 characters)'
  388. fi
  389. fi # end of overwriting check
  390. #    End of shell archive
  391. exit 0
  392.  
  393.